#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "fivekernel.h"

int **global_board;
int width = 15;
static int turn = BLACK;
static int last_x;
static int last_y;

static int judge(int **board, int width);

int krnl_init()
{
	int i;
	global_board = malloc(sizeof(int *) * width);
	for(i = 0; i < width; i++){
		global_board[i] = malloc(sizeof(int) * width);
		memset(global_board[i], EMPTY, sizeof(int) * width);
	}
	turn = BLACK;
	last_x = -1;
	last_y = -1;
	srand(time(NULL));
	return 0;
}

void krnl_reset()
{
	int i, j;
	for(i = 0; i < width; i++) {
		for (j = 0; j < width; j++) {
			global_board[i][j] = EMPTY;
		}
	}
	turn = BLACK;
	last_x = -1;
	last_y = -1;
	steps(0, 0, RESET, NULL);
}

int krnl_get_turn()
{
	return turn;
}

void krnl_get_last(int *x, int *y)
{
	*x = (last_x == -1) ? 0 : last_x;
	*y = (last_y == -1) ? 0 : last_y;
}

//此函数用于渲染
void krnl_get_last_pos(int *x, int *y)
{
	*x = last_x;
	*y = last_y;
}

int krnl_checker_put(int color, int x, int y, int *win)
{
	if (color != turn) return -1;
	if (global_board[y][x] != EMPTY) return -1;
	global_board[y][x] = color;
	last_x = x;
	last_y = y;
	steps(x, y, SAVE_STEP, NULL);
	//由于judge函数需要调用krnl_get_last和krnl_get_turn，
	//你必须在设置了last之后、turn之前调用该函数。
	*win = judge(global_board, 15);
	(color == BLACK) ? (turn = WHITE) : (turn = BLACK);
	return 0;
}

/*
 * 对下棋步骤的操作。
 * 由于使用了内部静态变量，该函数不是线程安全的，
 * 在线程环境里请加锁访问。
 */
void steps(int x, int y, int action, char *data)
{
	struct Steps{
		int x;
		int y;
	};
	static struct Steps* steps;
	static int position = 0, size=0, stepmax = 0;
	if(position == size)
	{
		size+=50;
		steps = realloc(steps, sizeof(struct Steps)*size);
		if(!steps)
			exit(1);
	}
	switch(action)
	{
		case SAVE_STEP:
			steps[position].x = x;
			steps[position].y = y;
			stepmax = position++;
			break;
		case PREV_STEP:
			break;
		case NEXT_STEP:
			break;
		case RESET:
			position = stepmax = 0;
			break;
		case SAVE_FILE:
			{
				FILE * fp;
				fp = fopen(data, "wb");
				int i;
				for(i=0; i<position; i++)
				{
					fprintf(fp, "%u %u\n", steps[i].x, steps[i].y);
				}
				fclose(fp);
			}
			break;
		case LOAD_FILE:
			{
				FILE *fp = fopen(data, "rb");
				char line[1024];
				int x, y, c=BLACK, win;
				while(fgets(line, 1024, fp))
				{
					sscanf(line, "%u %u", &x, &y);
					krnl_checker_put(c, x, y, &win);
					c = (c == BLACK) ? (WHITE) : (BLACK);
				}
				fclose(fp);
			}
			break;
	}
}

/*
 * Judge 函数负责判断胜负。
 * 在落子后、turn之前调用。
 * 传入参数分别为：
 *     board: 二维数组，描述棋盘，棋盘为正方形。
 *     width: 棋盘的大小为width*width
 * 返回值为int:
 *     0:   不胜不负
 *     正数: 胜
 *       1: 连五胜
 *       可能扩展为 TODO：
 *       三三胜
 *       三四胜
 *       四四胜
 *       活四胜
 *
 *     负数：禁手，负
 *       可能扩展为 TODO：
 *       三三禁手
 *       四四禁手
 *       等
 *
 */
static int judge(int **board, int width)
{
	//int i, j;
	int x, y, w = width;
	int turn;
	//int sum;

	turn = krnl_get_turn();
	krnl_get_last(&x, &y);//刚刚落子的位置
	int result[4];
	int score = point_score(turn, board, w, x, y, result);
	if(turn == BLACK && is_forbidden(result) < 0)
		return -1;

	if(score >= FIVE)
		return 1;
	else
		return 0;
}
